package com.wen.system.shiro.config;


import com.wen.system.shiro.filter.AJwtFilter2;
import com.wen.system.shiro.realm.LoginRealm;
import com.wen.system.shiro.realm.UserRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.SubjectContext;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration(proxyBeanMethods = true) // 是否代理bean的方法；true即为单例对象 （组件之间有依赖关系时用true）
public class ShiroConfig {

    private static final Logger log = LoggerFactory.getLogger(ShiroConfig.class);

    @Autowired
    private AJwtFilter2 jwtFilter;

    @Bean
    public DefaultWebSubjectFactory subjectFactory() {
        return new DefaultWebSubjectFactory(){
            @Override
            public Subject createSubject(SubjectContext context) {
                //不创建session
                context.setSessionCreationEnabled(false);
                return super.createSubject(context);
            }
        };
    }

    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager,
                                                         @Qualifier("shiroFilterChainDefinition") ShiroFilterChainDefinition shiroFilterChainDefinition) {

        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        //设置安全管理器
        factoryBean.setSecurityManager(defaultWebSecurityManager);

        //添加过滤器
        HashMap<String, Filter> filters = new HashMap<>();
        filters.put("jwt", jwtFilter);
        factoryBean.setFilters(filters);

        Map<String, String> filterMap = shiroFilterChainDefinition.getFilterChainMap();
        factoryBean.setFilterChainDefinitionMap(filterMap);


        /*
            1.anon:无需认证(登录)可以访问
            2.authc:必须认证才可以访问
            3.user:如果使用remember me 的功能可以直接访问
            4.perms:该资源必须得到资源权限才可以访问
            5.role:该资源必须得到角色权限才可以访问
        */
        /*
            //这里做权限设置
            LinkedHashMap<String, String> map = new LinkedHashMap<>();
            //把权限放入map里
            map.put("/main", "authc");
            map.put("/manage", "perms[manage]");
            map.put("/admin", "roles[admin]");
            map.put("/**","jwt");

            factoryBean.setFilterChainDefinitionMap(map);
        */

        //设置登录请求
        factoryBean.setLoginUrl("/open/login");
        //设置没有授权请求
        factoryBean.setUnauthorizedUrl("/open/unAuthc");
        return factoryBean;
    }

    /**
     * shiro的过滤器链 配置规则  （哪些链接需要经过那些过滤器）
     * */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        Map<String, String> filterMap = new LinkedHashMap<>();

        filterMap.put("/**", "jwt");
        filterMap.put("/user/login", "anon");
        filterMap.put("/content/*", "roles[author]");
        filterMap.put("/open/main", "authc");
        filterMap.put("/open/manage", "perms[manage]");
        filterMap.put("/open/admin", "roles[admin]");
//         filterMap.put("/role/**", "roles[admin]");
        // filterMap.put("/list", "jwt");
        // filterMap.put("/listVo", "jwt");
        chainDefinition.addPathDefinitions(filterMap);
        return chainDefinition;
    }

    /**
     * DefaultWebSecurityManager
     * */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm,
                                                               /*SessionManager sessionManager, //这里可以整合shiro-redis*/
                                                               EhCacheManager cacheManager) {

        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        // 设置多realm认证器的认证策略 , 默认AtLeastOneSuccessfulStrategy策略
        // defaultWebSecurityManager.setAuthenticator(new ModularRealmAuthenticator());

        ArrayList<Realm> list = new ArrayList<>();
        // list.add(this.loginRealm());
        list.add(userRealm);
        // defaultWebSecurityManager.setRealm(userRealm);
        defaultWebSecurityManager.setRealms(list);

        // 关闭Shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);

        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);

        // inject sessionManager
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionIdCookieEnabled(false);
        defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);

        defaultWebSecurityManager.setSessionManager(defaultWebSessionManager);
        // inject cacheManager
        defaultWebSecurityManager.setCacheManager(cacheManager);


        // 这点注意！！
        // ThreadContext.bind(defaultWebSecurityManager);
        return defaultWebSecurityManager;
    }

    /**
     * Realm
     * */
    @Bean
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();

        // 配置缓存管理器
        // userRealm.setCacheManager(new RedisCacheManager());
        // 开启全局缓存
        userRealm.setAuthenticationCachingEnabled(false);// 开启认证缓存
        userRealm.setAuthorizationCachingEnabled(false); // 开启授权缓存
        return userRealm;
    }

    //Realm
    @Bean
    public LoginRealm loginRealm() {
        return new LoginRealm();
    }


    /**
     * 会话管理器
     *
     * @return
     */
//    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        sessionManager.setSessionIdCookieEnabled(false);//禁用cookie
        sessionManager.setSessionIdUrlRewritingEnabled(false);//禁用url重写   url;jsessionid=id
        return sessionManager;
    }


    /**
     * 配置redisManager
     *
     * @return
     */
    public RedisManager getRedisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("127.0.0.1:6379");
        return redisManager;
    }

    /**
     * 配置具体cache实现类
     *
     * @return
     */
    public org.crazycake.shiro.RedisCacheManager cacheManager() {
        org.crazycake.shiro.RedisCacheManager redisCacheManager = new org.crazycake.shiro.RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());
        //设置redis过期时间，单位是秒
        redisCacheManager.setExpire(3600);
        redisCacheManager.setKeyPrefix("ihrm:shiro:cache:"); //设置权限信息缓存的名称前缀
        return redisCacheManager;
    }

    /**
     * 自定义session持久化
     *
     * @return
     */
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(getRedisManager());
        redisSessionDAO.setExpire(3600);
        redisSessionDAO.setKeyPrefix("ihrm:shiro:session:"); //设置session缓存的名称前缀
        return redisSessionDAO;
    }
    // 开启注解代理
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return ehCacheManager;
    }




}
